package com.iuie.ns.frame.persistence.dao.impl;

import java.io.Serializable;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.iuie.ns.frame.persistence.dao.IGenericDao;
import com.iuie.ns.frame.utils.CollectionUtils;
import com.iuie.ns.frame.utils.ReflectionUtils;
import com.iuie.ns.frame.web.dataset.vo.Page;

/**
 * DAO支持类实现
 * 
 * @author 莉
 * @param <T>
 * @date 2017年1月1日下午7:25:54
 * @param <T>
 */
@Repository("genericDao")
public class GenericDaoImpl<T> implements IGenericDao<T,Serializable> {

	@Autowired
	private SessionFactory sessionFactory;
	
	private Class<?> entityClass;

	public GenericDaoImpl() {
		entityClass = ReflectionUtils.getClassGenricType(getClass());
	}

	@Override
	public Session getCurrentSession() {
		return this.sessionFactory.getCurrentSession();
	}

	@Override
	public void clear() {
		getCurrentSession().clear();
	}

	@Override
	public Serializable save(T t) {
		return this.getCurrentSession().save(t);
	}
	
	@Override
	public void deleteById(Serializable id) {
		Session session = this.getCurrentSession();
		T t = this.findById(id);
		session.delete(t);
	}
	
	@Override
	public void delete(T t) {
		this.getCurrentSession().delete(t);
	}
	@Override
	public void update(T t) {
		this.getCurrentSession().update(t);
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<T> findAll() {
		return this.getCurrentSession().createCriteria(entityClass).setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY).list(); 
	}

	/*
	 * 查询条件的绑定
	 * @param t 查询条件参数
	 * @param map 查询条件参数的查询方式，即eq,lt,gt,like等
	 * @return
	 */
	private Criteria bindQuery(T t, Map<String, MatchType> map) {
		Criteria criteria = this.getCurrentSession().createCriteria(entityClass);
		// 当查询条件为空时，不需要组装查询条件
		if (t == null) {
			return criteria;
		}
		ObjectMapper mapper = new ObjectMapper();
		@SuppressWarnings("unchecked")
		Map<String, Object> params = mapper.convertValue(t, HashMap.class);
		
		Iterator<Entry<String, Object>> iterator = params.entrySet().iterator();
		while (iterator.hasNext()) {
			Entry<String, Object> entry = iterator.next();
			String key = entry.getKey();
			Object value = entry.getValue();
			
			if (value != null && CollectionUtils.isNotCollection(value)) {
				if (map == null || !map.containsKey(key) || map.get(key) == MatchType.MATCH_EQ) {
					// 默认eq
					criteria.add(Restrictions.eq(entry.getKey(), entry.getValue()));
				} else if (map.get(key) == MatchType.MATCH_LIKE) {
					criteria.add(Restrictions.like(entry.getKey(), "%"+entry.getValue()+"%"));
				} else if (map.get(key) == MatchType.MATCH_GT) {
					criteria.add(Restrictions.gt(entry.getKey(), entry.getValue()));
				} else if (map.get(key) == MatchType.MATCH_LT) {
					criteria.add(Restrictions.lt(entry.getKey(), entry.getValue()));
				}

			}
		}
		return criteria;
	}
	
	@Override
	public List<T> findAll(T t) {
		return this.findAll(t, null);
	}
	
	@Override
	public List<T> findAll(T t, Map<String, MatchType> map) {
		Criteria criteria = this.bindQuery(t, map);
		@SuppressWarnings("unchecked")
		List<T> result = criteria.list();
		return result;
	}

	/**
	 * 查询总条数
	 * @param t 查询的具体条件
	 * @param map criteria的查询条件描述
	 * @return
	 */
	protected int count(T t, Map<String, MatchType> map) {
		Criteria criteria = this.bindQuery(t, map);
		criteria.setProjection(Projections.rowCount());
		Object result = criteria.uniqueResult();
		Integer count = Integer.valueOf(result.toString());
		return count;
	}
	@Override
	public List<T> findByPage(T t, Page page, Map<String, MatchType> map) {
		int count = this.count(t, map);
		page.setCount(count);
		Criteria criteria = this.bindQuery(t, map);
		criteria.setFirstResult(page.getFirstRowNumber());
		int maxRowNumer = (int) page.getMaxRowNumber();
		criteria.setMaxResults(maxRowNumer);
		@SuppressWarnings("unchecked")
		List<T> list = criteria.list();
		return list;
	}
	
	@Override
	public int batchDelete(List<Integer> ids) {
		StringBuilder hql = new StringBuilder("delete from " + entityClass
				+ " where id in (:ids)");
		Query query = this.getCurrentSession().createQuery(hql.toString())
				.setParameterList("ids", ids);
		return query.executeUpdate();
	}
	@Override
	public boolean batchUpdate(List<T> list) {
		return false;
	}

	@Override
	public T findById(Serializable id) {
		@SuppressWarnings("unchecked")
		T t = (T) this.getCurrentSession().get(entityClass, id);
		return t;
	}

	@SuppressWarnings("unchecked")
	@Override
	public T load(Serializable id) {
		T t = (T) this.getCurrentSession().load(entityClass, id);
		return t;
	}

	@Override
	public void persist(T object) {
		this.getCurrentSession().persist(object);
	}

	@Override
	public Query createQuery(String hql) {
		return this.getCurrentSession().createQuery(hql);
	}

	@Override
	public void saveOrUpdate(T object) {
		this.getCurrentSession().saveOrUpdate(object);
	}
	
	@Override
	public List<T> findByPage(T t, Page page) {
		return this.findByPage(t, page, null);
	}
	
}
